﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using GlobalObjects;
using System.IO;
using System.Threading;
using EITSurferInfinityLib.DataProcessing;

namespace EITSurferInfinityLib
{
    public static class ParamManager
    {
        public static string[] Read(string FileName)
        { 
            string [] temp=null;
            try
            {
                temp=System.IO.File.ReadAllLines(FileName);
            }
            catch(Exception e)
            {
                Debug.WriteLine(e);
            }
            return temp;
        }

        static void Write(string [] ParamList, string FileName)
        {
                System.IO.File.WriteAllLines(FileName, ParamList);
        }

        public static void ProgramParameterByName(string FileName, string ParamName, string Value, ref VirtualDevice Device)
        {
            string[] read = Read(FileName);
            for (int i = 0; i < read.Length; i++)
            {
                if (read[i].Contains(ParamName))
                {
                    read[i] = ParamName + " " + Value;
                }
            }
            Write(read,FileName);
        }

        public static void ProgramParameter(string FileName, ref VirtualDevice Device)
        {
            string [] ParamList = Read(FileName);
            List<string> Param = ParamList.ToList();

            string CurrentFileName = "CurrentParameter.txt";

            Device.ADCSamplingPeriod = Device.ADCSamplingPeriodMin + (10e-9) * (int)GetParam(Param, "TSMP");

            Device.ImageRate= (int)GetParam(Param, "#imagerate");
            Device.NumberElectrode = (int)GetParam(Param, "#numberelectrode");

            Device.SettlingTime = Math.Round((int)GetParam(Param, "#settlingtime")*1e-6,7);
            int NIGN=(int)Math.Ceiling(TimeToPeriode(Device.SettlingTime, GetFrequency(Param, "NCO_F")));
            Device.SettlingTime = Math.Round(PeriodesToTime(NIGN, GetFrequency(Param, "NCO_F")), 7);

            Device.MeasurementTime = Math.Round((1.0 / Device.ImageRate) * (1.0 / (Device.NumberElectrode * Device.NumberElectrode)),7);
            int NPPW = (int)Math.Ceiling(TimeToPeriode(Device.MeasurementTime, GetFrequency(Param, "NCO_F")));
            Device.MeasurementTime = Math.Round(PeriodesToTime(NPPW,GetFrequency(Param, "NCO_F")),7);

            int NSMP = (int)Math.Floor((Device.MeasurementTime - Device.SettlingTime) / Device.ADCSamplingPeriod);
            //int NIGN=(int)Math.Ceiling(TimeToPeriode(Device.SettlingTime, GetFrequency(Param, "NCO_F")));
            //int NPPW = (int)Math.Ceiling(TimeToPeriode(Device.MeasurementTime, GetFrequency(Param, "NCO_F")));

            ProgramParameterByName(CurrentFileName, "NIGN", NIGN.ToString(), ref Device);
            ProgramParameterByName(CurrentFileName, "NPPW", NPPW.ToString(), ref Device);
            ProgramParameterByName(CurrentFileName, "NSMP", NSMP.ToString(), ref Device);

            //selection sclicing
            int fbit=0;
            if(NSMP>13207)
            {
                fbit=6;
            }
            else if(NSMP>3276)
            {
                fbit=5;
            }
            else if(NSMP>204)
            {
                fbit=4;
            }
            else if (NSMP > 50)
            {
                fbit = 3;
            }
            else if (NSMP > 12)
            {
                fbit = 2;
            }
            else if (NSMP > 3)
            {
                fbit = 1;
            }
            else
            {
                fbit = 0;
            }
            ProgramParameterByName(CurrentFileName, "NI0", fbit.ToString(), ref Device);
            ProgramParameterByName(CurrentFileName, "NQ0", fbit.ToString(), ref Device);
            int fbit2 = fbit - 0;
            if (fbit2 < 0)
            {
                fbit2 = 0;
            }
            ProgramParameterByName(CurrentFileName, "NI1 ", fbit2.ToString(), ref Device);
            ProgramParameterByName(CurrentFileName, "NQ1", fbit2.ToString(), ref Device);

            ParamList = Read(FileName);
            Param = ParamList.ToList();

            foreach (string s in ParamList)
            {
                if (!String.IsNullOrWhiteSpace(s))
                {
                    if (s.Contains("#") == false)
                    {
                        Thread.Sleep(10);
                        Device.Send("set " + s + "\n");
                    }
                }
            }

            //Device.SettlingTime = GetSettlingTime(Param);

            Device.Frequency = GetFrequency(Param, "NCO_F");
            Device.ToVoltParameter.NSample = (int)GetParam(Param, "NSMP");
            //Device.ToVoltParameter.FloatBits = 28-2*fbit;
            Device.ToVoltParameter.AnalogGain = GetAnalogGain(Param, Device.Frequency,72000,1000000);
            Device.ToVoltParameter.VRef = 2.048;
            Device.ToVoltParameter.CurrentA = GetCurrent(Param, Device.VRefDac, Device.CurrentSourceSettings, Device.Frequency, 1000000);


            Device.ToVoltParameter.FloatBits = 28 - 2 * fbit;
            SaveCurrentParam(ParamList);
        }

        private static object GetParam(List<string> Param, string ParamName)
        {
            List<string> ss = Param.FindAll(
                delegate(string s)
                {
                    return s.Contains(ParamName);
                });
            string[] temp = ss[0].Split(' ');
            return Convert.ToInt32(temp[1]);
        }

        private static double GetCurrent(List<string> Param, double vrefdac, double currentsourcesettings, double freq, double freqcut)
        {
            double current = 0;
            double CurrentParam=(int)GetParam(Param, "DAC_G");
            double z = currentsourcesettings + 1/(2 * Math.PI * freq * 220e-9);
            current = (vrefdac / 256.0) * CurrentParam / z;
            return current;
        }
        private static double GetSettlingTime(List<string> Param)
        {
            double periodes = (int)GetParam(Param, "NIGN");
            double frequency=GetFrequency(Param, "NCO_F");
            return PeriodesToTime(periodes, frequency);
        }

        private static double PeriodesToTime(double periodes, double frequency)
        {
            return (1 / frequency)*periodes;
        }

        private static double TimeToPeriode(double time, double frequency)
        {
            return time* frequency;
        }

        private static double GetFrequency(List<string> Param, string ParamName)
        {
            int value=(int)GetParam(Param, ParamName);
            return ValueToFrequency(value);
        }

        private static double ValueToFrequency(double value)
        {
            return 50000.0 + value * 10000.0;
        }

        private static double GetAnalogGain(List<string> Param, double freq, double freqcut, double freqcut2)
        {
            double AnalogGain = 0;

            List<string> gain0 = Param.FindAll(
                delegate(string s)
                {
                    return s.Contains("PGA0_G");
                });
            string[] tempGain0 = gain0[0].Split(' ');

            List<string> gain1 = Param.FindAll(
                delegate(string s)
                {
                    return s.Contains("PGA1_G");
                });
            string[] tempGain1 = gain1[0].Split(' ');

            switch (tempGain0[1])
            {
                case "0":
                    AnalogGain = 1;
                    break;
                case "1":
                    AnalogGain = 10;
                    break;
            }
            AnalogGain = AnalogGain * FilterAmplitude.HighPassAmplitude(freq, freqcut);
            switch (tempGain1[1])
            {
                case "0":
                    AnalogGain = AnalogGain * 1;
                    break;
                case "1":
                    AnalogGain = AnalogGain * 10;
                    break;
                case "2":
                    AnalogGain = AnalogGain * 20;
                    break;
                case "3":
                    AnalogGain = AnalogGain * 30;
                    break;
                case "4":
                    AnalogGain = AnalogGain * 40;
                    break;
                case "5":
                    AnalogGain = AnalogGain * 60;
                    break;
                case "6":
                    AnalogGain = AnalogGain * 80;
                    break;
                case "7":
                    AnalogGain = AnalogGain * 120;
                    break;
                case "8":
                    AnalogGain = AnalogGain * 157;
                    break;
            }
            AnalogGain = AnalogGain * FilterAmplitude.LowPassAmplitude(freq, freqcut2);
            return AnalogGain;
        }

        private static void SaveCurrentParam(string[] ParamList)
        {
            Write(ParamList, "CurrentParameter.txt");
        }
    }
}
